package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"server/base"
	"server/biz"
	"server/biz/proto"
	"time"

	"github.com/tidwall/gjson"
)

var client *http.Client

func init() {
	client = newClient()
}

func newClient() *http.Client {
	transport := &http.Transport{
		TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
		IdleConnTimeout:     300 * time.Second,
		MaxIdleConns:        1000,
		MaxIdleConnsPerHost: 500,
	}
	client := &http.Client{
		Transport: transport,
		Timeout:   30 * time.Second,
	}
	return client
}

func GetOrderTxt(id int) (string, error) {
	url := fmt.Sprintf("%s/v1/order/txt?id=%d", HOST, id)
	r, err := http.Get(url)
	if err != nil {
		return "", err
	}
	b, _ := io.ReadAll(r.Body)
	return string(b), nil
}

func Call(path string, in interface{}) (*gjson.Result, error) {
	b, err := json.Marshal(in)
	if err != nil {
		return nil, err
	}
	payload := bytes.NewReader(b)
	host := HOST
	url := fmt.Sprintf("%s%s", host, path)
	req, err := http.NewRequest("POST", url, payload)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")

	rsp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != 200 {
		err := fmt.Errorf("http-status:%d", rsp.StatusCode)
		return nil, err
	}

	data, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		return nil, err
	}
	result := gjson.ParseBytes(data)
	return &result, nil
}

func AskTask(bot_id string) (*proto.Task, error) {
	var in = map[string]any{
		"bot_id": bot_id,
	}
	r, err := Call("/v1/ask_task", in)
	if err != nil {
		return nil, err
	}
	ok := r.Get("ok").Bool()
	if !ok {
		des := r.Get("description").String()
		return nil, errors.New(des)
	}
	var out *proto.Task
	json.Unmarshal([]byte(r.Get("result").Raw), &out)
	return out, nil
}

func finTask(id int, e string) (*biz.FinResult, error) {
	in := &struct {
		Id    int    `json:"id"`
		Error string `json:"error"`
	}{
		Id:    id,
		Error: e,
	}
	r, err := Call("/v1/fin_task", in)
	if err != nil {
		return nil, err
	}
	ok := r.Get("ok").Bool()
	if !ok {
		des := r.Get("description").String()
		return nil, errors.New(des)
	}
	out := &biz.FinResult{}
	data := r.Get("result")
	finish := data.Get("finish").Bool()
	order_id := int(data.Get("order_id").Int())
	order_no := data.Get("order_no").String()
	out.Finish = finish
	out.OrderId = order_id
	out.OrderNo = order_no
	return out, nil
}

func FinTask(task *proto.Task, e string) error {
	r, err := finTask(task.Id, e)
	if err != nil {
		return err
	}
	log.Println("结果:", base.JsonString(r))
	if r.Finish && r.OrderNo != "" {
		txt, err := GetOrderTxt(r.OrderId)
		if err != nil {
			return err
		}
		filename := filepath.Join(task.Dst, fmt.Sprintf("%s.txt", r.OrderNo))
		f, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
		if err != nil {
			return err
		}
		f.WriteString(txt)
		f.Close()
	}
	return nil
}

func WaitingPkgs() ([]*proto.WaitingPkg, error) {
	r, err := Call("/v1/order/waitingPkgs", nil)
	if err != nil {
		return nil, err
	}
	ok := r.Get("ok").Bool()
	if !ok {
		des := r.Get("description").String()
		return nil, errors.New(des)
	}
	var out []*proto.WaitingPkg
	json.Unmarshal([]byte(r.Get("result").Raw), &out)
	return out, nil
}
